package org.springmvc.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springmvc.entity.BaseEntity;
import org.springmvc.exception.BusinessException;
import org.springmvc.json.JsonUtils;
import org.springmvc.mybatis.Mapper;

import java.time.Instant;
import java.util.List;

/**
 * 基础Service
 *
 * @author tangjialin on 2018-03-16.
 */
public abstract class BaseService<E extends BaseEntity> {

    @Autowired
    private Mapper<E> mapper;

    /**
     * 获取实体对象实例
     *
     * @param id 实体主键
     * @return 返回获取的实体对象实例
     */
    public E find(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    /**
     * 获取所有实体对象实例
     *
     * @return 返回获取的实体对象实例
     */
    public List<E> findAll() {
        return mapper.selectAll();
    }

    /**
     * 保存实体并设置实体必要公共属性
     *
     * @param e 期望添加的实体对象实例
     * @return 返回添加后的实体对象实例
     */
    @Transactional(rollbackFor = Exception.class)
    public E insert(E e) {
        if (e.getId() != null) { throw new BusinessException("主键必须为空"); }
        e.setVersion(1);
        e.setDeleted(false);
        if (e.getCreateTime() == null) { e.setCreateTime(Instant.now()); }
        if (e.getLastModifiedTime() == null) { e.setLastModifiedTime(e.getCreateTime()); }
        int insert = mapper.insertSelective(e);
        if (insert != 1) { throw new RuntimeException("数据插入失败:" + JsonUtils.toJson(e)); }
        return e;
    }

    /**
     * 新增或更新实体
     *
     * @param e 新增或更新的实体对象实例
     * @return 返回修改后的实体对象实例
     */
    @Transactional(rollbackFor = Exception.class)
    public E insertOrUpdate(E e) {
        if (e.getId() == null) {
            return insert(e);
        } else {
            return update(e);
        }
    }

    /**
     * 保存(修改)实体
     * 若属性为空,则该属性不会修改
     * 返回的实体创建时间会被置空
     *
     * @param e 期望保存的实体对象实例
     * @return 返回保存的实体对象实例, 返回的实体创建时间会被置空
     */
    @Transactional(rollbackFor = Exception.class)
    public E update(E e) {
        if (e.getId() == null) { throw new BusinessException("主键不能为空"); }
        if (e.getVersion() == null) {
            e.setVersion(mapper.selectVersionPrimaryKey(e.getId()));
        }
        if (e.getLastModifiedTime() == null) { e.setLastModifiedTime(Instant.now()); }
        // 更新数据不能更新创建时间
        e.setCreateTime(null);
        int update = mapper.updateByPrimaryKeySelective(e);
        if (update != 1) { throw new BusinessException("数据更新失败:" + JsonUtils.toJson(e)); }
        e.setVersion(e.getVersion() + 1);
        return e;
    }

    /**
     * 物理删除单实体
     *
     * @param e 期望删除的实体对象实例
     */
    @Transactional(rollbackFor = Exception.class)
    public int delete(E e) {
        if (e.getVersion() == null) { throw new BusinessException("[version]属性不能为空"); }
        int delete = mapper.deleteByPrimaryKey(e.getId());
        if (delete != 1) { throw new BusinessException("数据删除数与预期不符"); }
        return delete;
    }

    /**
     * 物理删除单实体
     *
     * @param id 期望删除的实体主键
     */
    @Transactional(rollbackFor = Exception.class)
    public int delete(Long id) {
        E entity = mapper.selectByPrimaryKey(id);
        if (entity == null) { throw new BusinessException("数据不存在"); }
        return delete(entity);
    }

}
